use std::env;

use anyhow::Result;
use bollard::{Docker, API_DEFAULT_VERSION};
use clap::Parser;
use deploy_service::{Args, Base, Commands, Config, DeployManager};
use tokio::fs;

#[tokio::main]
async fn main() -> Result<()> {
    let args = Args::parse();

    let curr_path = env::current_dir()?;
    let curr_path = curr_path.to_str().unwrap_or(".").to_owned();
    println!("current dir: {}", curr_path);

    let mut config = get_config().await.map_err(|e| {
        println!("get config fail, err: {}", e);
        e
    })?;
    config.curr_path = curr_path;

    let docker = connect_docker(&config.base).await.map_err(|e| {
        println!("connect docker fail, err: {}", e);
        e
    })?;

    let manager = DeployManager::new(docker, config);

    if let Some(commands) = args.commands {
        match commands {
            Commands::LoadImages => manager.load_images().await?,
            Commands::Start => manager.start_deploy().await?,
            Commands::Update { name } => manager.update_deploy(name).await?,
            Commands::Shutdown => manager.shutdown_deploy().await?,
            Commands::Clean => manager.clean_deploy().await?,
        }
    }

    Ok(())
}

async fn get_config() -> Result<Config> {
    let content = fs::read_to_string("./deploy.toml").await?;
    let config: Config = toml::from_str(&content)?;
    Ok(config)
}

async fn connect_docker(base: &Base) -> Result<Docker> {
    let docker = if let Some(unix) = &base.unix {
        Docker::connect_with_unix(unix, 30, API_DEFAULT_VERSION)?
    } else {
        Docker::connect_with_unix_defaults()?
    };

    let version = docker.version().await?;
    if let Some(components) = version.components {
        for component in components {
            println!("name:{}, version: {}", component.name, component.version);
        }
        println!();
    }

    Ok(docker)
}
